package com.mazaiting.manager.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.mazaiting.auth.constant.AuthConstant;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.common.core.ex.exceptions.BaseException;
import com.mazaiting.common.core.ex.exceptions.BusinessException;
import com.mazaiting.common.core.ex.exceptions.EmptyObjectException;
import com.mazaiting.web.domain.SingleResult;
import com.mazaiting.web.utils.UserUtil;
import com.mazaiting.manager.constant.SystemConstant;
import com.mazaiting.manager.convert.IUserConverter;
import com.mazaiting.manager.domain.dto.UserItemDto;
import com.mazaiting.manager.domain.entity.SysUser;
import com.mazaiting.manager.domain.entity.SysUserRole;
import com.mazaiting.manager.domain.form.UserForm;
import com.mazaiting.manager.domain.po.user.UserDetailPO;
import com.mazaiting.manager.domain.po.user.UserPO;
import com.mazaiting.manager.domain.query.UserPageQuery;
import com.mazaiting.manager.domain.vo.user.*;
import com.mazaiting.manager.dto.UserAuthDTO;
import com.mazaiting.manager.mapper.ISysUserMapper;
import com.mazaiting.manager.service.ISysRolePermissionService;
import com.mazaiting.manager.service.ISysUserRoleService;
import com.mazaiting.manager.service.ISysUserService;
import com.mazaiting.manager.utils.ExcelUtil;
import com.mazaiting.mybatisplus.domain.vo.BasePageVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * sys_user用户表 服务实现类
 *
 * @author mazaiting
 * @since 2022-03-22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<ISysUserMapper, SysUser> implements ISysUserService {

    private final IUserConverter userConverter;

    private final ISysUserRoleService sysUserRoleService;

    private final ISysRolePermissionService sysRolePermissionService;

    private final PasswordEncoder passwordEncoder;

    @Override
    public LoginUserVO getLoginUserInfo() throws EmptyObjectException {
        // 登录用户entity
        Optional<SysUser> sysUserOpt = lambdaQuery().eq(SysUser::getId, UserUtil.getUserId())
                .select(SysUser::getId, SysUser::getUsername).oneOpt();
        if (sysUserOpt.isEmpty()) {
            throw new EmptyObjectException(ResultCode.USER_NOT_EXIST);
        }
        // entity->BO
        LoginUserVO loginUserVO = userConverter.entity2LoginUser(sysUserOpt.get());
        // 用户角色集合
        List<String> roles = UserUtil.getRoles();
        loginUserVO.setRoles(roles);
        if (CollectionUtil.isEmpty(roles)) {
            throw new EmptyObjectException(ResultCode.ROLE_EMPTY);
        }
        // 用户按钮权限集合
        List<String> perms = sysRolePermissionService.listBtnPermByRoles(roles);
        loginUserVO.setPerms(perms);

        return loginUserVO;
    }

    @Override
    public UserAuthDTO getAuthInfoByUsername(String username) throws EmptyObjectException {
        Optional<UserAuthDTO> userAuthDTOOpt = baseMapper.getAuthInfoByUsername(username);
        return userAuthDTOOpt.orElseThrow(() -> new EmptyObjectException(ResultCode.USER_NOT_EXIST));
    }

    @Override
    public UserAuthDTO getAuthInfoByMobile(String mobile) throws EmptyObjectException {
        // 此处在SysUser进行扩展后可根据手机号查询用户名
        String username = "root";
        Optional<UserAuthDTO> userAuthDTOOpt = baseMapper.getAuthInfoByUsername(username);
        return userAuthDTOOpt.orElseThrow(() -> new EmptyObjectException(ResultCode.USER_NOT_EXIST));
    }

    @Override
    public List<UserExportVO> listExportUsers(UserPageQuery queryParams) {
        return baseMapper.listExportUsers(queryParams);
    }

    @Override
    public SingleResult importUsers(UserImportVO userImportVO) throws Exception {
        try {
            // 部门 ID
            Long deptId = userImportVO.getDeptId();
            // 角色 ID
            List<Long> roleIds = userImportVO.getRoleIds();
            // 文件流
            InputStream is = userImportVO.getFile().getInputStream();
            List<UserItemDto> list = ExcelUtil.readSync(is, UserItemDto.class);
            if (CollectionUtil.isEmpty(list)) {
                log.error("excel 中用户列表数据为空");
                throw new EmptyObjectException(ResultCode.USER_LIST_EMPTY);
            }

            // 有效数据集合 - 过滤用户名为空的数据
            List<UserItemDto> validDataList = list.stream().filter(item -> StrUtil.isNotBlank(item.getUsername())).toList();
            if (CollectionUtil.isEmpty(validDataList)) {
                log.error("excel 中用户有效列表数据为空");
                throw new EmptyObjectException(ResultCode.USER_LIST_VALID_EMPTY);
            }

            // 校验是否有用户名重复
            long distinctCount = validDataList.stream()
                    .map(UserItemDto::getUsername)
                    .distinct()
                    .count();
            if (distinctCount != validDataList.size()) {
                log.error("excel 中用户列表包含重复的用户名");
                throw new BusinessException(ResultCode.USER_LIST_CONTAINS_REPEAT_NAME);
            }

            StringBuilder errMsg = new StringBuilder();

            // 批量保存到数据
            List<SysUser> saveUserList = Lists.newArrayList();
            // 遍历
            for (UserItemDto userItemDto : validDataList) {
                // 用户名
                String username = userItemDto.getUsername();
                // 密码
                String password = userItemDto.getPassword();
                SysUser user = new SysUser();
                user.setUsername(username);
                user.setDeptId(deptId);
                // 默认密码
                password = StringUtils.hasLength(password) ? password : SystemConstant.DEFAULT_USER_PASSWORD;
                user.setPassword(passwordEncoder.encode(password));

                saveUserList.add(user);
            }

            // 需要保存的用户列表不为空
            if (CollectionUtil.isNotEmpty(saveUserList)) {
                // 批量保存
                boolean result = this.saveBatch(saveUserList);
                if (!result) {
                    log.error("excel 导入数据失败, 原因: 保存用户出错");
                    throw new BusinessException(ResultCode.USER_IMPORT_FAILED);
                }
                // 用户角色
                List<SysUserRole> userRoleList = new ArrayList<>();

                if (CollectionUtil.isNotEmpty(roleIds)) {
                    roleIds.forEach(roleId -> userRoleList.addAll(saveUserList.stream().map(user -> new SysUserRole(user.getId(), roleId)).toList()));
                }
                // 批量保存用户角色关系
                sysUserRoleService.saveBatch(userRoleList);
            }

            errMsg.append(String.format("一共%d条数据，成功导入%d条数据，导入失败数据%d条", list.size(), saveUserList.size(), list.size() - saveUserList.size()));
            return new SingleResult(errMsg.toString());
        } catch (Exception e) {
            log.error("导入用户数据异常: {}.", e.getMessage());
            throw e;
        }
    }

    @Override
    public BasePageVO<SysUserVO> listUserPages(UserPageQuery queryParams) {
        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        Page<UserPO> page = new Page<>(pageNum, pageSize);
        // 查询数据
        Page<UserPO> userPoPage = baseMapper.listUserPages(page, queryParams);

        // 实体转换
        Page<SysUserVO> sysUserVOPage = userConverter.po2Vo(userPoPage);

        return BasePageVO.success(sysUserVOPage);
    }

    @Override
    public UserDetailVO getUserDetail(Long userId) throws EmptyObjectException {
        UserDetailPO userDetailPO = this.baseMapper.getUserDetail(userId);
        if (Objects.isNull(userDetailPO)) {
            throw new EmptyObjectException(ResultCode.USER_NOT_EXIST);
        }
        // 实体转换po->form
        return userConverter.po2Vo(userDetailPO);
    }

    @Override
    public boolean update(UserForm userForm) throws BaseException {
        // 根据用户名查询用户是否已存在
        String username = userForm.getUsername();
        Long count = lambdaQuery().eq(SysUser::getUsername, username)
                .ne(SysUser::getId, userForm.getId())
                .count();
        if (count > 0) {
            throw new BusinessException(ResultCode.USER_ACCOUNT_ALREADY_EXIST);
        }

        // 根据 ID 查询用户是否存在
        SysUser sysUser = baseMapper.selectById(userForm.getId());
        if (Objects.isNull(sysUser)) {
            throw new EmptyObjectException(ResultCode.USER_NOT_EXIST);
        }
        // form -> entity
        userConverter.form2Entity(userForm, sysUser);

        // 修改用户
        boolean result = updateById(sysUser);
        // 修改成功则更新角色
        if (result) {
            // 保存用户角色
            result = sysUserRoleService.saveUserRoles(sysUser.getId(), userForm.getRoleIds());
        }
        return result;
    }

    @Override
    public boolean save(UserForm userForm) throws BaseException {
        // 将 ID 置为 null
        userForm.setId(null);
        // 根据用户名查询用户是否已存在
        String username = userForm.getUsername();
        Long count = lambdaQuery().eq(SysUser::getUsername, username).count();
        if (count > 0) {
            throw new BusinessException(ResultCode.USER_ACCOUNT_ALREADY_EXIST);
        }

        // form -> entity
        SysUser sysUser = userConverter.form2Entity(userForm);

        // 设置默认的密码
        sysUser.setPassword(passwordEncoder.encode(SystemConstant.DEFAULT_USER_PASSWORD));

        boolean result = save(sysUser);
        // 用户保存成功然后保存用户角色关系
        if (result) {
            result = sysUserRoleService.saveUserRoles(sysUser.getId(), userForm.getRoleIds());
        }

        return result;
    }

    @Override
    public boolean delete(String ids) throws BaseException {
        if (!StringUtils.hasLength(ids)) {
            throw new EmptyObjectException(ResultCode.USER_ID_NULL);
        }

        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
        // 判断是否包含 root 用户
        if (idList.contains(AuthConstant.AUTH_ROOT_ID)) {
            throw new BusinessException(ResultCode.USER_NOT_DELETE_ROOT);
        }
        // 先删除用户角色关系, 不论删除关系是否成功, 都执行删除用户
        sysUserRoleService.deleteByUserIds(idList);
        // 删除用户
        return removeByIds(idList);
    }

    @Override
    public boolean updatePassword(Long userId, String password) throws EmptyObjectException {
        // 判断用户是否存在
        Optional<SysUser> sysUserOpt = lambdaQuery().eq(SysUser::getId, userId).oneOpt();
        if (sysUserOpt.isEmpty()) {
            throw new EmptyObjectException(ResultCode.USER_NOT_EXIST);
        }
        // 获取用户
        SysUser sysUser = sysUserOpt.get();
        sysUser.setPassword(passwordEncoder.encode(password));
        return updateById(sysUser);
    }

    @Override
    public boolean updateEnabled(Long userId, Boolean enabled) throws EmptyObjectException {
        // 判断用户是否存在
        Optional<SysUser> sysUserOpt = lambdaQuery().eq(SysUser::getId, userId).oneOpt();
        if (sysUserOpt.isEmpty()) {
            throw new EmptyObjectException(ResultCode.USER_NOT_EXIST);
        }
        // 获取用户
        SysUser sysUser = sysUserOpt.get();
        sysUser.setEnabled(enabled);
        return updateById(sysUser);
    }

}
